home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 7: Sunsite / Linux Cubed Series 7 - Sunsite Vol 1.iso / system / shells / zsh-3.0-p / zsh-3 / zsh-3.0-pre3 / Src / lex.c < prev    next >
C/C++ Source or Header  |  1996-07-14  |  26KB  |  1,317 lines

  1. /*
  2.  * $Id: lex.c,v 2.35 1996/07/13 20:26:35 hzoli Exp $
  3.  *
  4.  * lex.c - lexical analysis
  5.  *
  6.  * This file is part of zsh, the Z shell.
  7.  *
  8.  * Copyright (c) 1992-1996 Paul Falstad
  9.  * All rights reserved.
  10.  *
  11.  * Permission is hereby granted, without written agreement and without
  12.  * license or royalty fees, to use, copy, modify, and distribute this
  13.  * software and its documentation for any purpose, provided that the
  14.  * above copyright notice and the following two paragraphs appear in
  15.  * all copies of this software.
  16.  *
  17.  * In no event shall Paul Falstad or the Zsh Development Group be liable
  18.  * to any party for direct, indirect, special, incidental, or consequential
  19.  * damages arising out of the use of this software and its documentation,
  20.  * even if Paul Falstad and the Zsh Development Group have been advised of
  21.  * the possibility of such damage.
  22.  *
  23.  * Paul Falstad and the Zsh Development Group specifically disclaim any
  24.  * warranties, including, but not limited to, the implied warranties of
  25.  * merchantability and fitness for a particular purpose.  The software
  26.  * provided hereunder is on an "as is" basis, and Paul Falstad and the
  27.  * Zsh Development Group have no obligation to provide maintenance,
  28.  * support, updates, enhancements, or modifications.
  29.  *
  30.  */
  31.  
  32. #include "zsh.h"
  33.  
  34. /* lexical state */
  35.  
  36. static int dbparens;
  37. int len = 0, bsiz = 256;
  38. char *bptr;
  39. extern int hwgetword;
  40.  
  41. struct lexstack {
  42.     struct lexstack *next;
  43.  
  44.     int incmdpos;
  45.     int incond;
  46.     int incasepat;
  47.     int dbparens;
  48.     int alstat;
  49.     int isfirstln;
  50.     int isfirstch;
  51.     int histremmed;
  52.     int histdone;
  53.     int spaceflag;
  54.     int stophist;
  55.     int hlinesz;
  56.     char *hline;
  57.     char *hptr;
  58.     int tok;
  59.     int isnewlin;
  60.     char *tokstr;
  61.     char *yytext;
  62.     char *bptr;
  63.     int bsiz;
  64.     short *chwords;
  65.     int chwordlen;
  66.     int chwordpos;
  67.     int hwgetword;
  68.     struct heredocs *hdocs;
  69.  
  70.     unsigned char *cstack;
  71.     int csp;
  72. };
  73.  
  74. static struct lexstack *lstack = NULL;
  75.  
  76. /* History word status variables from hist.c */
  77. extern short *chwords;
  78. extern int chwordlen, chwordpos;
  79.  
  80. /* save the lexical state */
  81.  
  82. /* is this a hack or what? */
  83.  
  84. /**/
  85. void
  86. lexsave(void)
  87. {
  88.     struct lexstack *ls;
  89.  
  90.     DPUTS(alstackind, "BUG: lexsave called with alstackind != 0");
  91.     ls = (struct lexstack *)malloc(sizeof(struct lexstack));
  92.  
  93.     ls->incmdpos = incmdpos;
  94.     ls->incond = incond;
  95.     ls->incasepat = incasepat;
  96.     ls->dbparens = dbparens;
  97.     ls->alstat = alstat;
  98.     ls->isfirstln = isfirstln;
  99.     ls->isfirstch = isfirstch;
  100.     ls->histremmed = histremmed;
  101.     ls->histdone = histdone;
  102.     ls->spaceflag = spaceflag;
  103.     ls->stophist = stophist;
  104.     ls->hline = chline;
  105.     ls->hptr = hptr;
  106.     ls->hlinesz = hlinesz;
  107.     ls->cstack = cmdstack;
  108.     ls->csp = cmdsp;
  109.     cmdstack = (unsigned char *)zalloc(256);
  110.     ls->tok = tok;
  111.     ls->isnewlin = isnewlin;
  112.     ls->tokstr = tokstr;
  113.     ls->yytext = yytext;
  114.     ls->bptr = bptr;
  115.     ls->bsiz = bsiz;
  116.     ls->chwords = chwords;
  117.     ls->chwordlen = chwordlen;
  118.     ls->chwordpos = chwordpos;
  119.     ls->hwgetword = hwgetword;
  120.     ls->hdocs = hdocs;
  121.     cmdsp = 0;
  122.     inredir = 0;
  123.     hdocs = NULL;
  124.  
  125.     ls->next = lstack;
  126.     lstack = ls;
  127. }
  128.  
  129. /* restore lexical state */
  130.  
  131. /**/
  132. void
  133. lexrestore(void)
  134. {
  135.     struct lexstack *ln;
  136.  
  137.     if (!lstack) {
  138.     zerr("lexrestore without lexsave", NULL, 0);
  139.     return;
  140.     }
  141.     incmdpos = lstack->incmdpos;
  142.     incond = lstack->incond;
  143.     incasepat = lstack->incasepat;
  144.     dbparens = lstack->dbparens;
  145.     alstat = lstack->alstat;
  146.     isfirstln = lstack->isfirstln;
  147.     isfirstch = lstack->isfirstch;
  148.     histremmed = lstack->histremmed;
  149.     histdone = lstack->histdone;
  150.     spaceflag = lstack->spaceflag;
  151.     stophist = lstack->stophist;
  152.     chline = lstack->hline;
  153.     hptr = lstack->hptr;
  154.     if (cmdstack)
  155.     free(cmdstack);
  156.     cmdstack = lstack->cstack;
  157.     cmdsp = lstack->csp;
  158.     tok = lstack->tok;
  159.     isnewlin = lstack->isnewlin;
  160.     tokstr = lstack->tokstr;
  161.     yytext = lstack->yytext;
  162.     bptr = lstack->bptr;
  163.     bsiz = lstack->bsiz;
  164.     chwords = lstack->chwords;
  165.     chwordlen = lstack->chwordlen;
  166.     chwordpos = lstack->chwordpos;
  167.     hwgetword = lstack->hwgetword;
  168.     hdocs = lstack->hdocs;
  169.     clearalstack();
  170.     hlinesz = lstack->hlinesz;
  171.     lexstop = errflag = 0;
  172.  
  173.     ln = lstack->next;
  174.     free(lstack);
  175.     lstack = ln;
  176. }
  177.  
  178. /**/
  179. void
  180. yylex(void)
  181. {
  182.     if (tok == LEXERR)
  183.     return;
  184.     do
  185.     tok = gettok();
  186.     while (tok != ENDINPUT && exalias());
  187.     if (tok == NEWLIN || tok == ENDINPUT) {
  188.     while (hdocs) {
  189.         struct heredocs *next = hdocs->next;
  190.  
  191.         hwbegin(0);
  192.         cmdpush(hdocs->rd->type == HEREDOC ? CS_HEREDOC : CS_HEREDOCD);
  193.         STOPHIST
  194.         hdocs->rd->name = gethere(hdocs->rd->name, hdocs->rd->type);
  195.         ALLOWHIST
  196.         cmdpop();
  197.         hwend();
  198.         hdocs->rd->type = HERESTR;
  199.         zfree(hdocs, sizeof(struct heredocs));
  200.         hdocs = next;
  201.     }
  202.     }
  203.     if (tok != NEWLIN)
  204.     isnewlin = 0;
  205.     else
  206.     isnewlin = (inbufct) ? -1 : 1;
  207.     if (tok == SEMI || tok == NEWLIN)
  208.     tok = SEPER;
  209. }
  210.  
  211. /**/
  212. void
  213. ctxtlex(void)
  214. {
  215.     static int oldpos;
  216.  
  217.     yylex();
  218.     switch (tok) {
  219.     case SEPER:
  220.     case NEWLIN:
  221.     case SEMI:
  222.     case DSEMI:
  223.     case AMPER:
  224.     case AMPERBANG:
  225.     case INPAR:
  226.     case INBRACE:
  227.     case DBAR:
  228.     case DAMPER:
  229.     case BAR:
  230.     case BARAMP:
  231.     case INOUTPAR:
  232.     case DO:
  233.     case THEN:
  234.     case ELIF:
  235.     case ELSE:
  236.     case DOUTBRACK:
  237.     incmdpos = 1;
  238.     break;
  239.     case STRING:
  240.  /* case ENVSTRING: */
  241.     case ENVARRAY:
  242.     case OUTPAR:
  243.     case CASE:
  244.     case DINBRACK:
  245.     incmdpos = 0;
  246.     break;
  247.     }
  248.     if (IS_REDIROP(tok) || tok == FOR || tok == FOREACH || tok == SELECT) {
  249.     inredir = 1;
  250.     oldpos = incmdpos;
  251.     incmdpos = 0;
  252.     } else if (inredir) {
  253.     incmdpos = oldpos;
  254.     inredir = 0;
  255.     }
  256. }
  257.  
  258. #define LX1_BKSLASH 0
  259. #define LX1_COMMENT 1
  260. #define LX1_NEWLIN 2
  261. #define LX1_SEMI 3
  262. #define LX1_AMPER 5
  263. #define LX1_BAR 6
  264. #define LX1_INPAR 7
  265. #define LX1_OUTPAR 8
  266. #define LX1_INANG 13
  267. #define LX1_OUTANG 14
  268. #define LX1_OTHER 15
  269.  
  270. #define LX2_BREAK 0
  271. #define LX2_OUTPAR 1
  272. #define LX2_BAR 2
  273. #define LX2_STRING 3
  274. #define LX2_INBRACK 4
  275. #define LX2_OUTBRACK 5
  276. #define LX2_TILDE 6
  277. #define LX2_INPAR 7
  278. #define LX2_INBRACE 8
  279. #define LX2_OUTBRACE 9
  280. #define LX2_OUTANG 10
  281. #define LX2_INANG 11
  282. #define LX2_EQUALS 12
  283. #define LX2_BKSLASH 13
  284. #define LX2_QUOTE 14
  285. #define LX2_DQUOTE 15
  286. #define LX2_BQUOTE 16
  287. #define LX2_COMMA 17
  288. #define LX2_OTHER 18
  289. #define LX2_META 19
  290.  
  291. unsigned char lexact1[256], lexact2[256], lextok2[256];
  292.  
  293. /**/
  294. void
  295. initlextabs(void)
  296. {
  297.     int t0;
  298.     static char *lx1 = "\\q\n;!&|(){}[]<>";
  299.     static char *lx2 = ";)|$[]~({}><=\\\'\"`,";
  300.  
  301.     for (t0 = 0; t0 != 256; t0++) {
  302.     lexact1[t0] = LX1_OTHER;
  303.     lexact2[t0] = LX2_OTHER;
  304.     lextok2[t0] = t0;
  305.     }
  306.     for (t0 = 0; lx1[t0]; t0++)
  307.     lexact1[(int)lx1[t0]] = t0;
  308.     for (t0 = 0; lx2[t0]; t0++)
  309.     lexact2[(int)lx2[t0]] = t0;
  310.     lexact2['&'] = LX2_BREAK;
  311.     lexact2[STOUC(Meta)] = LX2_META;
  312.     lextok2['*'] = Star;
  313.     lextok2['?'] = Quest;
  314.     lextok2['{'] = Inbrace;
  315.     lextok2['['] = Inbrack;
  316.     lextok2['$'] = String;
  317.     lextok2['~'] = Tilde;
  318. }
  319.  
  320. /* initialize lexical state */
  321.  
  322. /**/
  323. void
  324. lexinit(void)
  325. {
  326.     incond = incasepat = nocorrect =
  327.     dbparens = alstat = lexstop = 0;
  328.     incmdpos = 1;
  329.     tok = ENDINPUT;
  330.     if (isset(EXTENDEDGLOB)) {
  331.     lextok2['#'] = Pound;
  332.     lextok2['^'] = Hat;
  333.     } else {
  334.     lextok2['#'] = '#';
  335.     lextok2['^'] = '^';
  336.     }
  337. }
  338.  
  339. /* add a char to the string buffer */
  340.  
  341. /**/
  342. void
  343. add(int c)
  344. {
  345.     *bptr++ = c;
  346.     if (bsiz == ++len) {
  347.     int newbsiz;
  348.  
  349.     newbsiz = bsiz * 8;
  350.     while (newbsiz < inbufct)
  351.         newbsiz *= 2;
  352.     bptr = len + (tokstr = (char *)hrealloc(tokstr, bsiz, newbsiz));
  353.     bsiz = newbsiz;
  354.     }
  355. }
  356.  
  357. #define SETPARBEGIN {if (zleparse && !alstackind && cs >= ll+1-inbufct) parbegin = inbufct;}
  358. #define SETPAREND {\
  359.         if (zleparse && !alstackind && parbegin != -1 && parend == -1)\
  360.         if (cs >= ll + 1 - inbufct)\
  361.             parbegin = -1;\
  362.         else\
  363.             parend = inbufct;}
  364.  
  365. /**/
  366. int
  367. gettok(void)
  368. {
  369.     int c, d;
  370.     int peekfd = -1, peek;
  371.  
  372.     MUSTUSEHEAP("gettok");
  373.   beginning:
  374.     tokstr = NULL;
  375.     while (iblank(c = hgetc()) && !lexstop);
  376.     isfirstln = 0;
  377.     wordbeg = inbufct - (qbang && c == bangchar);
  378.     hwbegin(-1);        /* word includes the last character read */
  379.     if (dbparens) {
  380.     len = 0;
  381.     bptr = tokstr = (char *)ncalloc(bsiz = 256);
  382.     hungetc(c);
  383.     cmdpush(CS_MATH);
  384.     c = dquote_parse(')', 0);
  385.     cmdpop();
  386.     if (c || (c = hgetc()) != ')') {
  387.         hungetc(c);
  388.         *bptr = '\0';
  389.         return LEXERR;
  390.     }
  391.     dbparens = 0;
  392.     *bptr = '\0';
  393.     return DOUTPAR;
  394.     } else if (idigit(c)) {    /* handle 1< foo */
  395.     d = hgetc();
  396.     hungetc(d);
  397.     lexstop = 0;
  398.     if (d == '>' || d == '<') {
  399.         peekfd = c - '0';
  400.         c = hgetc();
  401.     }
  402.     }
  403.  
  404.     /* chars in initial position in word */
  405.  
  406.     if (c == hashchar &&
  407.     (isset(INTERACTIVECOMMENTS) ||
  408.      (!zleparse && !expanding &&
  409.       (!interact || unset(SHINSTDIN) || strin)))) {
  410.     /* History is handled here to prevent extra  *
  411.      * newlines being inserted into the history. */
  412.  
  413.     while ((c = ingetc()) != '\n' && !lexstop) {
  414.         hwaddc(c);
  415.         addtoline(c);
  416.     }
  417.  
  418.     if (errflag)
  419.         peek = LEXERR;
  420.     else {
  421.         hwend();
  422.         hwbegin(0);
  423.         hwaddc('\n');
  424.         addtoline('\n');
  425.         peek = NEWLIN;
  426.     }
  427.     return peek;
  428.     }
  429.     if (lexstop)
  430.     return (errflag) ? LEXERR : ENDINPUT;
  431.     switch (lexact1[STOUC(c)]) {
  432.     case LX1_BKSLASH:
  433.     d = hgetc();
  434.     if (d == '\n')
  435.         goto beginning;
  436.     hungetc(d);
  437.     lexstop = 0;
  438.     break;
  439.     case LX1_NEWLIN:
  440.     return NEWLIN;
  441.     case LX1_SEMI:
  442.     d = hgetc();
  443.     if (d != ';') {
  444.         hungetc(d);
  445.         lexstop = 0;
  446.         return SEMI;
  447.     }
  448.     return DSEMI;
  449.     case LX1_AMPER:
  450.     d = hgetc();
  451.     if (d == '&')
  452.         return DAMPER;
  453.     else if (d == '!' || d == '|')
  454.         return AMPERBANG;
  455.     else if (d == '>') {
  456.         d = hgetc();
  457.         if (d == '!' || d == '|')
  458.         return OUTANGAMPBANG;
  459.         else if (d == '>') {
  460.         d = hgetc();
  461.         if (d == '!' || d == '|')
  462.             return DOUTANGAMPBANG;
  463.         hungetc(d);
  464.         lexstop = 0;
  465.         return DOUTANGAMP;
  466.         }
  467.         hungetc(d);
  468.         lexstop = 0;
  469.         return AMPOUTANG;
  470.     }
  471.     hungetc(d);
  472.     lexstop = 0;
  473.     return AMPER;
  474.     case LX1_BAR:
  475.     d = hgetc();
  476.     if (d == '|')
  477.         return DBAR;
  478.     else if (d == '&')
  479.         return BARAMP;
  480.     hungetc(d);
  481.     lexstop = 0;
  482.     return BAR;
  483.     case LX1_INPAR:
  484.     d = hgetc();
  485.     if (d == '(' && incmdpos) {
  486.         dbparens = 1;
  487.         return DINPAR;
  488.     } else if (d == ')')
  489.         return INOUTPAR;
  490.     hungetc(d);
  491.     lexstop = 0;
  492.     if (!(incond == 1 || incmdpos))
  493.         break;
  494.     return INPAR;
  495.     case LX1_OUTPAR:
  496.     return OUTPAR;
  497.     case LX1_INANG:
  498.     d = hgetc();
  499.     if ((!incmdpos && d == '(') || incasepat) {
  500.         hungetc(d);
  501.         lexstop = 0;
  502.         break;
  503.     }
  504.     if (d == '>')
  505.         peek = INOUTANG;
  506.     else if (idigit(d) || d == '-') {
  507.         int tbs = 256, n = 0, nc;
  508.         char *tbuf, *tbp, *ntb;
  509.  
  510.         tbuf = tbp = (char *)zalloc(tbs);
  511.         hungetc(d);
  512.  
  513.         while ((nc = hgetc()) && !lexstop) {
  514.         if (!idigit(nc) && nc != '-')
  515.             break;
  516.         *tbp++ = (char)nc;
  517.         if (++n == tbs) {
  518.             ntb = (char *)realloc(tbuf, tbs *= 2);
  519.             tbp += ntb - tbuf;
  520.             tbuf = ntb;
  521.         }
  522.         }
  523.         if (nc == '>' && !lexstop) {
  524.         hungetc(nc);
  525.         while (n--)
  526.             hungetc(*--tbp);
  527.         zfree(tbuf, tbs);
  528.         break;
  529.         }
  530.         if (nc && !lexstop)
  531.         hungetc(nc);
  532.         lexstop = 0;
  533.         while (n--)
  534.         hungetc(*--tbp);
  535.         zfree(tbuf, tbs);
  536.         peek = INANG;
  537.     } else if (d == '<') {
  538.         int e = hgetc();
  539.  
  540.         if (e == '(') {
  541.         hungetc(e);
  542.         hungetc(d);
  543.         peek = INANG;
  544.         } else if (e == '<')
  545.         peek = TRINANG;
  546.         else if (e == '-')
  547.         peek = DINANGDASH;
  548.         else {
  549.         hungetc(e);
  550.         lexstop = 0;
  551.         peek = DINANG;
  552.         }
  553.     } else if (d == '&')
  554.         peek = INANGAMP;
  555.     else {
  556.         peek = INANG;
  557.         hungetc(d);
  558.         lexstop = 0;
  559.     }
  560.     tokfd = peekfd;
  561.     return peek;
  562.     case LX1_OUTANG:
  563.     d = hgetc();
  564.     if (d == '(') {
  565.         hungetc(d);
  566.         break;
  567.     } else if (d == '&') {
  568.         d = hgetc();
  569.         if (d == '!' || d == '|')
  570.         peek = OUTANGAMPBANG;
  571.         else {
  572.         hungetc(d);
  573.         lexstop = 0;
  574.         peek = OUTANGAMP;
  575.         }
  576.     } else if (d == '!' || d == '|')
  577.         peek = OUTANGBANG;
  578.     else if (d == '>') {
  579.         d = hgetc();
  580.         if (d == '&') {
  581.         d = hgetc();
  582.         if (d == '!' || d == '|')
  583.             peek = DOUTANGAMPBANG;
  584.         else {
  585.             hungetc(d);
  586.             lexstop = 0;
  587.             peek = DOUTANGAMP;
  588.         }
  589.         } else if (d == '!' || d == '|')
  590.         peek = DOUTANGBANG;
  591.         else if (d == '(') {
  592.         hungetc(d);
  593.         hungetc('>');
  594.         peek = OUTANG;
  595.         } else {
  596.         hungetc(d);
  597.         lexstop = 0;
  598.         peek = DOUTANG;
  599.         if (isset(HISTALLOWCLOBBER))
  600.             hwaddc('|');
  601.         }
  602.     } else {
  603.         hungetc(d);
  604.         lexstop = 0;
  605.         peek = OUTANG;
  606.         if (!incond && isset(HISTALLOWCLOBBER))
  607.         hwaddc('|');
  608.     }
  609.     tokfd = peekfd;
  610.     return peek;
  611.     }
  612.  
  613.     /* we've started a string, now get the *
  614.      * rest of it, performing tokenization */
  615.     return gettokstr(c, 0);
  616. }
  617.  
  618. /**/
  619. int
  620. gettokstr(int c, int sub)
  621. {
  622.     int bct = 0, pct = 0, brct = 0;
  623.     int intpos = 1, in_brace_param = 0;
  624.     int peek, inquote;
  625. #ifdef DEBUG
  626.     int ocmdsp = cmdsp;
  627. #endif
  628.  
  629.     peek = STRING;
  630.     if (!sub) {
  631.     len = 0;
  632.     bptr = tokstr = (char *)ncalloc(bsiz = 256);
  633.     }
  634.     for (;;) {
  635.     int act;
  636.     int e;
  637.  
  638.     if (inblank(c) && !in_brace_param && !pct)
  639.         act = LX2_BREAK;
  640.     else {
  641.         act = lexact2[STOUC(c)];
  642.         c = lextok2[STOUC(c)];
  643.     }
  644.     switch (act) {
  645.     case LX2_BREAK:
  646.         if (!in_brace_param && !sub)
  647.         goto brk;
  648.         break;
  649.     case LX2_META:
  650.         c = hgetc();
  651. #ifdef DEBUG
  652.         if (lexstop) {
  653.         fputs("BUG: input terminated by Meta\n", stderr);
  654.         fflush(stderr);
  655.         goto brk;
  656.         }
  657. #endif
  658.         add(Meta);
  659.         break;
  660.     case LX2_OUTPAR:
  661.         if ((sub || in_brace_param) && isset(SHGLOB))
  662.         break;
  663.         if (!in_brace_param && !pct--)
  664.         if (sub) {
  665.             pct = 0;
  666.             break;
  667.         } else
  668.             goto brk;
  669.         c = Outpar;
  670.         break;
  671.     case LX2_BAR:
  672.         if (!pct && !in_brace_param)
  673.         if (sub)
  674.             break;
  675.         else
  676.             goto brk;
  677.         if (unset(SHGLOB) || (!sub && !in_brace_param))
  678.         c = Bar;
  679.         break;
  680.     case LX2_STRING:
  681.         e = hgetc();
  682.         if (e == '[') {
  683.         cmdpush(CS_MATHSUBST);
  684.         add(String);
  685.         add(Inbrack);
  686.         c = dquote_parse(']', sub);
  687.         cmdpop();
  688.         if (c) {
  689.             peek = LEXERR;
  690.             goto brk;
  691.         }
  692.         c = Outbrack;
  693.         } else if (e == '(') {
  694.         add(String);
  695.         c = hgetc();
  696.         if (c == '(') {
  697.             add(Inpar);
  698.             add('(');
  699.             cmdpush(CS_MATHSUBST);
  700.             if (!(c = dquote_parse(')', sub))) {
  701.             add(')');
  702.             if ((c = hgetc()) == ')')
  703.                 c = 0;
  704.             }
  705.             cmdpop();
  706.         }
  707.         else {
  708.             hungetc(c);
  709.             lexstop = 0;
  710.             c = skipcomm();
  711.         }
  712.         if (c) {
  713.             peek = LEXERR;
  714.             goto brk;
  715.         }
  716.         c = Outpar;
  717.         } else {
  718.         if (e == '{') {
  719.             add(c);
  720.             c = Inbrace;
  721.             ++bct;
  722.             cmdpush(CS_BRACEPAR);
  723.             if (!in_brace_param)
  724.             in_brace_param = bct;
  725.         } else {
  726.             hungetc(e);
  727.             lexstop = 0;
  728.         }
  729.         }
  730.         break;
  731.     case LX2_INBRACK:
  732.         add(c);
  733.         if (!in_brace_param)
  734.         brct++;
  735.         c = hgetc();
  736.         if (c == '!' || c == '^') {
  737.         add(c);
  738.         c = hgetc();
  739.         }
  740.         if (c == ']')
  741.         break;
  742.         if (lexstop)
  743.         goto brk;
  744.         intpos = 0;
  745.         continue;
  746.     case LX2_OUTBRACK:
  747.         if (brct < 0) {
  748.         brct = 0;
  749.         break;
  750.         }
  751.         c = Outbrack;
  752.         break;
  753.     case LX2_INPAR:
  754.         if ((sub || in_brace_param) && isset(SHGLOB))
  755.         break;
  756.         if (!in_brace_param) {
  757.         if (!sub) {
  758.             e = hgetc();
  759.             hungetc(e);
  760.             lexstop = 0;
  761.             if (e == ')' ||
  762.             (incmdpos && !brct && peek != ENVSTRING))
  763.             goto brk;
  764.         }
  765.         pct++;
  766.         }
  767.         c = Inpar;
  768.         break;
  769.     case LX2_INBRACE:
  770.         if (isset(IGNOREBRACES) || sub)
  771.         c = '{';
  772.         else {
  773.         if (in_brace_param)
  774.             cmdpush(CS_BRACE);
  775.         bct++;
  776.         }
  777.         break;
  778.     case LX2_OUTBRACE:
  779.         if (!bct || ((isset(IGNOREBRACES) || sub) && !in_brace_param))
  780.         break;
  781.         if (in_brace_param)
  782.         cmdpop();
  783.         if (bct-- == in_brace_param)
  784.         in_brace_param = 0;
  785.         c = Outbrace;
  786.         break;
  787.     case LX2_COMMA:
  788.         if (unset(IGNOREBRACES) && !sub && bct > in_brace_param)
  789.         c = Comma;
  790.         break;
  791.     case LX2_OUTANG:
  792.         if (!intpos)
  793.         if (in_brace_param || sub)
  794.             break;
  795.         else
  796.             goto brk;
  797.         e = hgetc();
  798.         if (e != '(') {
  799.         hungetc(e);
  800.         lexstop = 0;
  801.         goto brk;
  802.         }
  803.         add(Outang);
  804.         if (skipcomm()) {
  805.         peek = LEXERR;
  806.         goto brk;
  807.         }
  808.         c = Outpar;
  809.         break;
  810.     case LX2_INANG:
  811.         if (isset(SHGLOB) && sub)
  812.         break;
  813.         e = hgetc();
  814.         if (!(idigit(e) || e == '-' || (e == '(' && intpos))) {
  815.         hungetc(e);
  816.         lexstop = 0;
  817.         if (in_brace_param || sub)
  818.             break;
  819.         goto brk;
  820.         }
  821.         c = Inang;
  822.         if (e == '(') {
  823.         add(c);
  824.         if (skipcomm()) {
  825.             peek = LEXERR;
  826.             goto brk;
  827.         }
  828.         c = Outpar;
  829.         } else {
  830.         add(c);
  831.         c = e;
  832.         while (c != '>' && !lexstop)
  833.             add(c), c = hgetc();
  834.         c = Outang;
  835.         }
  836.         break;
  837.     case LX2_EQUALS:
  838.         if (intpos) {
  839.         e = hgetc();
  840.         if (e != '(') {
  841.             hungetc(e);
  842.             lexstop = 0;
  843.             c = Equals;
  844.         } else {
  845.             add(Equals);
  846.             if (skipcomm()) {
  847.             peek = LEXERR;
  848.             goto brk;
  849.             }
  850.             c = Outpar;
  851.         }
  852.         } else if (!sub && peek != ENVSTRING &&
  853.                incmdpos && !bct && !brct) {
  854.         e = hgetc();
  855.         if (e == '(' && incmdpos) {
  856.             *bptr = '\0';
  857.             return ENVARRAY;
  858.         }
  859.         hungetc(e);
  860.         lexstop = 0;
  861.         peek = ENVSTRING;
  862.         intpos = 2;
  863.         } else
  864.         c = Equals;
  865.         break;
  866.     case LX2_BKSLASH:
  867.         c = hgetc();
  868.         if (c == '\n') {
  869.         c = hgetc();
  870.         if (!lexstop)
  871.             continue;
  872.         } else
  873.         add(Bnull);
  874.         if (lexstop)
  875.         goto brk;
  876.         break;
  877.     case LX2_QUOTE:
  878.         add(Snull);
  879.         cmdpush(CS_QUOTE);
  880.         for (;;) {
  881.         STOPHIST
  882.         while ((c = hgetc()) != '\'' && !lexstop) {
  883.             if (!sub && isset(CSHJUNKIEQUOTES) && c == '\n') {
  884.             if (bptr[-1] == '\\')
  885.                 bptr--, len--;
  886.             else
  887.                 break;
  888.             }
  889.             add(c);
  890.         }
  891.         ALLOWHIST
  892.         if (c != '\'') {
  893.             zerr("unmatched \'", NULL, 0);
  894.             peek = LEXERR;
  895.             cmdpop();
  896.             goto brk;
  897.         }
  898.         e = hgetc();
  899.         if (e != '\'' || unset(RCQUOTES))
  900.             break;
  901.         add(c);
  902.         }
  903.         cmdpop();
  904.         hungetc(e);
  905.         lexstop = 0;
  906.         c = Snull;
  907.         break;
  908.     case LX2_DQUOTE:
  909.         add(Dnull);
  910.         cmdpush(CS_DQUOTE);
  911.         c = dquote_parse('"', sub);
  912.         cmdpop();
  913.         if (c) {
  914.         zerr("unmatched \"", NULL, 0);
  915.         peek = LEXERR;
  916.         goto brk;
  917.         }
  918.         c = Dnull;
  919.         break;
  920.     case LX2_BQUOTE:
  921.         add(Tick);
  922.         cmdpush(CS_BQUOTE);
  923.         SETPARBEGIN
  924.         inquote = 0;
  925.         while ((c = hgetc()) != '`' && !lexstop)
  926.         if (c == '\\') {
  927.             c = hgetc();
  928.             if (c != '\n') {
  929.             add(c == '`' || c == '\\' || c == '$' ? Bnull : '\\');
  930.             add(c);
  931.             }
  932.             else if (!sub && isset(CSHJUNKIEQUOTES))
  933.             add(c);
  934.         } else {
  935.             if (!sub && isset(CSHJUNKIEQUOTES) && c == '\n') {
  936.             break;
  937.             }
  938.             add(c);
  939.             if (c == '\'')
  940.             if ((inquote = !inquote))
  941.                 STOPHIST
  942.             else
  943.                 ALLOWHIST
  944.         }
  945.         if (inquote)
  946.         ALLOWHIST
  947.         cmdpop();
  948.         if (c != '`') {
  949.         zerr("unmatched `", NULL, 0);
  950.         peek = LEXERR;
  951.         goto brk;
  952.         }
  953.         c = Tick;
  954.         SETPAREND
  955.         break;
  956.     }
  957.     add(c);
  958.     c = hgetc();
  959.     if (intpos)
  960.         intpos--;
  961.     if (lexstop)
  962.         break;
  963.     }
  964.   brk:
  965.     hungetc(c);
  966.     *bptr = '\0';
  967.     DPUTS(cmdsp != ocmdsp, "BUG: gettok: cmdstack changed.");
  968.     return peek;
  969. }
  970.  
  971. extern int addedx;
  972.  
  973. /**/
  974. int
  975. dquote_parse(char endchar, int sub)
  976. {
  977.     int pct = 0, brct = 0, bct = 0, intick = 0, err = 0;
  978.     int c;
  979.     int math = endchar == ')' || endchar == ']';
  980.     int zlemath = math && cs > ll + addedx - inbufct;
  981.  
  982.     while (((c = hgetc()) != endchar || bct ||
  983.         (math && ((pct > 0) || (brct > 0))) ||
  984.         intick) && !lexstop) {
  985.     switch (c) {
  986.     case '\\':
  987.         c = hgetc();
  988.         if (c != '\n')
  989.         add(c == '$' || c == '\\' || (c == '}' && !intick && bct) ||
  990.             c == '\"' || c == '`' ? Bnull : '\\');
  991.         else if (sub || unset(CSHJUNKIEQUOTES) || endchar != '"')
  992.         continue;
  993.         break;
  994.     case '\n':
  995.         err = !sub && isset(CSHJUNKIEQUOTES) && endchar == '"';
  996.         break;
  997.     case '$':
  998.         if (intick)
  999.         break;
  1000.         c = hgetc();
  1001.         if (c == '(') {
  1002.         add(Qstring);
  1003.         c = hgetc();
  1004.         if (c == '(') {
  1005.             add(Inpar);
  1006.             add('(');
  1007.             cmdpush(CS_MATHSUBST);
  1008.             if (!(err = dquote_parse(')', sub))) {
  1009.             add(')');
  1010.             if ((err = hgetc()) == ')')
  1011.                 err = 0;
  1012.             }
  1013.             cmdpop();
  1014.         }
  1015.         else {
  1016.             hungetc(c);
  1017.             lexstop = 0;
  1018.             err = skipcomm();
  1019.         }
  1020.         c = Outpar;
  1021.         } else if (c == '[') {
  1022.         add(String);
  1023.         add(Inbrack);
  1024.         cmdpush(CS_MATHSUBST);
  1025.         err = dquote_parse(']', sub);
  1026.         cmdpop();
  1027.         c = Outbrack;
  1028.         } else if (c == '{') {
  1029.         add(Qstring);
  1030.         c = Inbrace;
  1031.         cmdpush(CS_BRACEPAR);
  1032.         bct++;
  1033.         } else if (c == '$')
  1034.         add(Qstring);
  1035.         else {
  1036.         hungetc(c);
  1037.         lexstop = 0;
  1038.         c = Qstring;
  1039.         }
  1040.         break;
  1041.     case '}':
  1042.         if (intick || !bct)
  1043.         break;
  1044.         c = Outbrace;
  1045.         bct--;
  1046.         cmdpop();
  1047.         break;
  1048.     case '`':
  1049.         c = Qtick;
  1050.         if (intick == 2)
  1051.         ALLOWHIST
  1052.         if ((intick = !intick)) {
  1053.         SETPARBEGIN
  1054.         cmdpush(CS_BQUOTE);
  1055.         } else {
  1056.         SETPAREND
  1057.             cmdpop();
  1058.         }
  1059.         break;
  1060.     case '\'':
  1061.         if (!intick)
  1062.         break;
  1063.         if (intick == 1)
  1064.         intick = 2, STOPHIST
  1065.         else
  1066.         intick = 1, ALLOWHIST
  1067.         break;
  1068.     case '(':
  1069.         pct++;
  1070.         break;
  1071.     case ')':
  1072.         err = (!pct-- && math);
  1073.         break;
  1074.     case '[':
  1075.         brct++;
  1076.         break;
  1077.     case ']':
  1078.         err = (!brct-- && math);
  1079.         break;
  1080.     case '"':
  1081.         if (intick || !endchar)
  1082.         break;
  1083.         if (bct) {
  1084.         add(Dnull);
  1085.         err = dquote_parse('"', sub);
  1086.         c = Dnull;
  1087.         } else
  1088.         err = 1;
  1089.         break;
  1090.     }
  1091.     if (err || lexstop)
  1092.         break;
  1093.     add(c);
  1094.     }
  1095.     if (intick == 2)
  1096.     ALLOWHIST
  1097.     if (intick)
  1098.     cmdpop();
  1099.     while (bct--)
  1100.     cmdpop();
  1101.     if (lexstop)
  1102.     err = intick || endchar || err;
  1103.     else if (err == 1)
  1104.     err = c;
  1105.     if (zlemath && cs <= ll + 1 - inbufct)
  1106.     inwhat = IN_MATH;
  1107.     return err;
  1108. }
  1109.  
  1110. /* Tokenize a string given in s. Parsing is done as in double *
  1111.  * quotes.  This is usually called before singsub().          */
  1112.  
  1113. /**/
  1114. int
  1115. parsestr(char *s)
  1116. {
  1117.     int l = strlen(s), err;
  1118.  
  1119.     HEAPALLOC {
  1120.     lexsave();
  1121.     untokenize(s);
  1122.     inpush(dupstring(s), 0);
  1123.     strinbeg();
  1124.     stophist = 2;
  1125.     len = 0;
  1126.     bptr = tokstr = s;
  1127.     bsiz = l + 1;
  1128.     err = dquote_parse('\0', 1);
  1129.     *bptr = '\0';
  1130.     strinend();
  1131.     inpop();
  1132.     DPUTS(cmdsp, "BUG: parsestr: cmdstack not empty.");
  1133.     lexrestore();
  1134.     if (err) {
  1135.         untokenize(s);
  1136.         if (err > 32 && err < 127)
  1137.         zerr("parse error near `%c'", NULL, err);
  1138.         else
  1139.         zerr("parse error", NULL, 0);
  1140.     }
  1141.     } LASTALLOC;
  1142.     return err;
  1143. }
  1144.  
  1145. /* Tokenize a string given in s. Parsing is done as if s were a normal *
  1146.  * command-line argument but it may contain separators.  This is used  *
  1147.  * to parse the right-hand side of ${...%...} substitutions.           */
  1148.  
  1149. /**/
  1150. int
  1151. parse_subst_string(char *s)
  1152. {
  1153.     int c, l = strlen(s), err;
  1154.  
  1155.     if (! *s)
  1156.     return 0;
  1157.     lexsave();
  1158.     untokenize(s);
  1159.     inpush(dupstring(s), 0);
  1160.     strinbeg();
  1161.     stophist = 2;
  1162.     len = 0;
  1163.     bptr = tokstr = s;
  1164.     bsiz = l + 1;
  1165.     c = hgetc();
  1166.     c = gettokstr(c, 1);
  1167.     err = errflag;
  1168.     strinend();
  1169.     inpop();
  1170.     DPUTS(cmdsp, "BUG: parse_subst_string: cmdstack not empty.");
  1171.     lexrestore();
  1172.     errflag = err;
  1173.     if (c == LEXERR) {
  1174.     untokenize(s);
  1175.     return 1;
  1176.     }
  1177. #ifdef DEBUG
  1178.     if (c != STRING || len != l || errflag) {
  1179.     fprintf(stderr, "Oops. Bug in parse_subst_string: %s\n",
  1180.         len < l ? "len < l" : errflag ? "errflag" : "c != STRING");
  1181.     fflush(stderr);
  1182.     untokenize(s);
  1183.     return 1;
  1184.     }
  1185. #endif
  1186.     return 0;
  1187. }
  1188.  
  1189. /* expand aliases and reserved words */
  1190.  
  1191. /**/
  1192. int
  1193. exalias(void)
  1194. {
  1195.     Alias an;
  1196.     Reswd rw;
  1197.  
  1198.     hwend();
  1199.     if (interact && isset(SHINSTDIN) && !strin && !incasepat &&
  1200.     tok == STRING && !nocorrect && !alstackind &&
  1201.     (isset(CORRECTALL) || (isset(CORRECT) && incmdpos)))
  1202.     spckword(&tokstr, 1, incmdpos, 1);
  1203.  
  1204.     if (!tokstr) {
  1205.     yytext = tokstrings[tok];
  1206.     if (yytext)
  1207.         yytext = dupstring(yytext);
  1208.     return 0;
  1209.     }
  1210.  
  1211.     if (has_token(tokstr)) {
  1212.     char *p, *t;
  1213.  
  1214.     yytext = p = ncalloc(strlen(tokstr) + 1);
  1215.     for (t = tokstr; (*p++ = itok(*t) ? ztokens[*t++ - Pound] : *t++););
  1216.     } else
  1217.     yytext = tokstr;
  1218.  
  1219.     if (zleparse && !alstackind) {
  1220.     int zp = zleparse;
  1221.  
  1222.     gotword();
  1223.     if (zp && !zleparse) {
  1224.         return 0;
  1225.     }
  1226.     }
  1227.  
  1228.     /* Check for an alias */
  1229.     an = noaliases ? NULL : (Alias) aliastab->getnode(aliastab, yytext);
  1230.     if (alstackind != MAXAL && an && !an->inuse &&
  1231.     ((an->flags & ALIAS_GLOBAL) || incmdpos || alstat == ALSTAT_MORE)) {
  1232.     an->inuse = 1;
  1233.     inpush((alstack[alstackind++] = an)->text, INP_ALIAS);
  1234.     alstat = 0;
  1235.     /* remove from history if it begins with space */
  1236.     if (isset(HISTIGNORESPACE) && an->text[0] == ' ')
  1237.         remhist();
  1238.     lexstop = 0;
  1239.     return 1;
  1240.     }
  1241.  
  1242.     if (tok == STRING) {
  1243.     /* Then check for a reserved word */
  1244.     if ((incmdpos || (tokstr[0] == '}' && !tokstr[1])) &&
  1245.         (rw = (Reswd) reswdtab->getnode(reswdtab, yytext))) {
  1246.         tok = rw->token;
  1247.         if (tok == DINBRACK)
  1248.         incond = 1;
  1249.     } else if (incond && !strcmp(yytext, "]]")) {
  1250.         tok = DOUTBRACK;
  1251.         incond = 0;
  1252.     } else if (incond && yytext[0] == '!' && !yytext[1])
  1253.         tok = BANG;
  1254.     }
  1255.     return 0;
  1256. }
  1257.  
  1258. /* skip (...) */
  1259.  
  1260. /**/
  1261. int
  1262. skipcomm(void)
  1263. {
  1264.     int pct = 1, c;
  1265.  
  1266.     cmdpush(CS_CMDSUBST);
  1267.     SETPARBEGIN
  1268.     c = Inpar;
  1269.     do {
  1270.     add(c);
  1271.     c = hgetc();
  1272.     if (itok(c) || lexstop)
  1273.         break;
  1274.     switch (c) {
  1275.     case '(':
  1276.         pct++;
  1277.         break;
  1278.     case ')':
  1279.         pct--;
  1280.         break;
  1281.     case '\\':
  1282.         add(c);
  1283.         c = hgetc();
  1284.         break;
  1285.     case '\'':
  1286.         add(c);
  1287.         STOPHIST
  1288.         while ((c = hgetc()) != '\'' && !lexstop)
  1289.         add(c);
  1290.         ALLOWHIST
  1291.         break;
  1292.     case '\"':
  1293.         add(c);
  1294.         while ((c = hgetc()) != '\"' && !lexstop)
  1295.         if (c == '\\') {
  1296.             add(c);
  1297.             add(hgetc());
  1298.         } else
  1299.             add(c);
  1300.         break;
  1301.     case '`':
  1302.         add(c);
  1303.         while ((c = hgetc()) != '`' && !lexstop)
  1304.         if (c == '\\')
  1305.             add(c), add(hgetc());
  1306.         else
  1307.             add(c);
  1308.         break;
  1309.     }
  1310.     }
  1311.     while (pct);
  1312.     if (!lexstop)
  1313.     SETPAREND
  1314.     cmdpop();
  1315.     return lexstop;
  1316. }
  1317.